package com.jifeng.sterilizer.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.jifeng.sterilizer.constant.WXUrlConstant;
import com.jifeng.sterilizer.dto.DeviceFarmDTO;
import com.jifeng.sterilizer.entity.*;
import com.jifeng.sterilizer.service.*;
import com.jifeng.sterilizer.utils.*;
import com.jifeng.sterilizer.vo.DeviceEntityVo;
import com.jifeng.sterilizer.vo.ReturnDeviceEntityVo;
import com.sun.org.apache.xerces.internal.dom.DeepNodeListImpl;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import org.bouncycastle.pqc.math.linearalgebra.IntUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.jifeng.sterilizer.dao.DeviceDao;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


@Service("deviceService")
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceDao, DeviceEntity> implements DeviceService {

    @Autowired
    LiquidService liquidService;

    @Autowired
    LiquidTypeService liquidTypeService;

    @Autowired
    private UserDeviceService userDeviceService;

    @Autowired
    FarmService farmService;

    @Autowired
    DeviceTypeService deviceTypeService;

    @Override
    public R calculateDeviceWorkTime(Map<String, Object> params) {
        try {

            // 获取参数
            Integer length = Convert.toInt(params.get("length"));
            Integer width = Convert.toInt(params.get("width"));
            Integer height = Convert.toInt(params.get("height"));
            String deviceId = Convert.toStr(params.get("number"));

            // 校验各参数值的合法性
            if (length == 0 || width == 0 || height == 0 || StrUtil.isEmpty(deviceId)) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "各参数值不可缺少");
                return R.error(400, "各参数值不可缺少");
            }
            if (!RegexUtils.isNumber(deviceId, 1)) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "消毒机编号格式错误");
                return R.error(400, "消毒机编号格式错误");
            }

            DeviceEntity deviceEntity = this.getOne(new QueryWrapper<DeviceEntity>().eq("number", deviceId), false);
            if (deviceEntity == null) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "消毒机编号无效");
                return R.error(400, "消毒机编号无效");
            }

            // 获取设备中的药剂编号
            String liquidNumber = deviceEntity.getLiquidNumber();
            if (!RegexUtils.isNumber(Convert.toStr(liquidNumber), 0)) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "消毒机未绑定药剂或药剂编号格式错误");
                return R.error(400, "消毒机未绑定药剂或药剂编号格式错误");
            }

            // 根据设备中的药剂编号查询药剂
            LiquidEntity liquidEntity = liquidService.getOne(new QueryWrapper<LiquidEntity>().eq("number", liquidNumber), false);
            if (liquidEntity == null) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "药剂编号无效");
                return R.error(400, "药剂编号无效");
            }

            // 根据药剂获取药剂编号
            Long liquidTypeId = liquidEntity.getLiquidTypeId();
            if (liquidTypeId == null || liquidTypeId == 0) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "药剂类型id无效");
                return R.error(400, "药剂类型id无效");
            }

            // 查询药剂类型
            LiquidTypeEntity liquidTypeEntity = liquidTypeService.getOne(new QueryWrapper<LiquidTypeEntity>().eq("id", liquidTypeId), false);
            if (liquidTypeEntity == null) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "未找到相关的药剂类型");
                return R.error(400, "未找到相关的药剂类型");
            }

            // 获取相关需要计算的值
            Float radio = liquidTypeEntity.getRatio();
            Float capacity = liquidTypeEntity.getCapacity();
            if (radio == null || capacity == null) {
                log.warn("方法：{}，错误信息：{}", "计算工作时长", "未找到相关的药剂类型");
                return R.error(400, "药剂容量或单位喷洒比为空");
            }
            Float rs = (length * width * height * 1000) / (radio * capacity);
            return R.ok().put("data", rs);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "计算工作时长", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    private HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }


    @Override
    public R getDeviceInfoWx(Map<String, String> params) {
        try {
            // 获取请求
            HttpServletRequest request = getRequest();

            // 得到参数中的用户ID
            Integer userId = Convert.toInt(params.get("userId"));

            // 从token中获取用户信息
            Map userInfo = HttpUtils.getTokenInfo(request);

            // 从用户信息中得到用户ID
            Integer tokenId = Convert.toInt(userInfo.get("id"));

            // 判断是否是同一用户
            if (!tokenId.equals(userId)) {
                log.warn("方法：{}，错误信息：{}", "小程序接口->获取消毒机信息", "只能查询本用户的数据");
                return R.error(400, "只能查询本用户的数据");
            }

            // 如果是同一用户则获取消毒机信息
            String deviceNumber = Convert.toStr(params.get("device_id"));

            // 校验消毒机编号格式
            if (!RegexUtils.isNumber(deviceNumber, 1)) {
                log.warn("方法：{}，错误信息：{}", "小程序接口->获取消毒机信息", "消毒机编号格式错误");
                return R.error(400, "消毒机编号格式错误");
            }

            // 查询消毒机信息
            UserDeviceEntity userDeviceEntity = userDeviceService.getOne(new QueryWrapper<UserDeviceEntity>().eq("user_id", userId).eq("device_number", deviceNumber), false);

            // 校验消毒机是否存在
            if (userDeviceEntity == null) {
                log.warn("方法：{}，错误信息：{}", "小程序接口->获取消毒机信息", "该用户未绑定该消毒机");
                return R.error(400, "该用户未绑定该消毒机");
            }
            Map<String, Object> map = new HashMap<>();
            map.put("device_id", deviceNumber);
            return getDevicesInfo(map);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "小程序接口->获取消毒机信息", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R mySave(DeviceEntityVo device) {
        DeviceEntity deviceEntity = new DeviceEntity();
        BeanUtils.copyProperties(device, deviceEntity);
        boolean save = this.save(deviceEntity);
        if (save) {
            return R.ok();
        }
        return R.error();
    }

    @Override
    public R updateByNumber(DeviceEntityVo device) {
        Map<String, Object> errMap = new HashMap<>();
        Long number = device.getNumber();
        DeviceEntity deviceEntity = this.getOne(new QueryWrapper<DeviceEntity>().eq("number", number));
        if (deviceEntity == null) {
            errMap.put("number", "无效的设备编号");
        }
        if (!errMap.isEmpty()) {
            return R.error().put("data", errMap);
        }
        DeviceEntity updateDeviceEntity = new DeviceEntity();
        BeanUtils.copyProperties(device, updateDeviceEntity);
        boolean update = this.update(updateDeviceEntity, new QueryWrapper<DeviceEntity>().eq("number", number));
        if (update) {
            return R.ok();
        }
        return R.error();
    }

    @Override
    public R monitor(Map<String, Object> params) {
        try {
            // 获取参数消毒机编号
            String deviceId = Convert.toStr(params.get("device_id"));

            DeviceEntity deviceEntity = this.getOne(new QueryWrapper<DeviceEntity>().eq("number", deviceId), false);
            if (deviceEntity == null) {
                return R.error(400, "设备编号无效");
            }

            // 属性拷贝
            DeviceFarmDTO deviceFarmDTO = new DeviceFarmDTO();
            BeanUtils.copyProperties(deviceEntity, deviceFarmDTO);

            // 查询消毒机关联的农场
            FarmEntity farmEntity = farmService.getById(deviceEntity.getFarmId());
            if (farmEntity == null) {
                return R.error(400, "农场未找到");
            }

            // 查询消毒机类型
            DeviceTypeEntity deviceTypeEntity = deviceTypeService.getById(deviceEntity.getDeviceTypeId());
            if (deviceTypeEntity == null) {
                return R.error(400, "消毒机类型未找到");
            }

            deviceFarmDTO.setFarmName(farmEntity.getName());
            deviceFarmDTO.setTypeName(deviceTypeEntity.getName());
            return R.ok().put("data", deviceFarmDTO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "上限|下限温度|运行定时|加热状态|工作状态修改|清洗保养|后台、本机 PC", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    /**
     * @param params {"number":"11111111111","Method":"temp_target","value":"200"} {number:xxx,Method:"temp_baseline",value:"200"}
     *               {number:xxx,Method:" run_set_time",value:"200"} {number:xxx,Method:"device_heat_status",value:"0"}
     *               {number:xxx,Method:"work_status",value:"0|1|2|3"} {number:xxx,Method:"clean",value:"1"}
     * @return {code:"200",msg:"成功"}
     */
    @Override
    public R callDevUpdate(Map<String, Object> params) {
        try {
            // 获取参数值
            String method = Convert.toStr(params.get("Method"));
            String number = Convert.toStr(params.get("number"));
            String value = Convert.toStr(params.get("value"));

            // 判断消毒机编号格式
            if (!RegexUtils.isNumber(number, 1)) {
                log.warn("方法：{}，错误信息：{}", "上限|下限温度|运行定时|加热状态|工作状态修改|清洗保养|后台、本机 PC", "消毒机编号格式错误");
                return R.error(400, "消毒机编号格式错误");
            }

            if ("temp_target".equals(method)) {
                boolean aTrue = HttpUtils.setLimitTemp(number, "true", value);
                if (!aTrue) {
                    return R.error(400, "请求下位机发生异常");
                }
            } else if ("temp_baseline".equals(method)) {
                boolean aFalse = HttpUtils.setLimitTemp(number, "false", value);
                if (!aFalse) {
                    return R.error(400, "请求下位机发生异常");
                }
            } else if ("run_set_time".equals(method)) {
                boolean b = HttpUtils.setRunTime(number, value);
                if (!b) {
                    return R.error(400, "请求下位机发生异常");
                }
            } else if ("device_heat_status".equals(method)) {
                if (!"0".equals(value) && !"1".equals(value)) {
                    return R.error(400, "状态值只能为0或1");
                }
                boolean b = HttpUtils.setheatCmd(number, value);
                if (!b) {
                    return R.error(400, "请求下位机发生异常");
                }
            } else if ("work_status".equals(method)) {
                if (!"0".equals(value) && !"1".equals(value) && !"2".equals(value)
                        && !"3".equals(value)) {
                    return R.error(400, "状态值只能为0|1|2|3");
                }
                boolean b = HttpUtils.setRunCmd(number, value);
                if (!b) {
                    return R.error(400, "请求下位机发生异常");
                }
            } else if ("clean".equals(method)) {
                if (!"1".equals(value)) {
                    return R.error(400, "状态值只能为1");
                }
                boolean b = HttpUtils.setCleanCmd(number, value);
                if (!b) {
                    return R.error(400, "请求下位机发生异常");
                }
            } else if ("mode".equals(method)) {
                boolean b = HttpUtils.setWorkMode(number, value);
                if (!b) {
                    return R.error(400, "请求下位机发生异常");
                }
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "上限|下限温度|运行定时|加热状态|工作状态修改|清洗保养|后台、本机 PC", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R callDevUpdateTimeRun(Map<String, Object> params) {
        try {

            // 获取参数
            Integer number = Convert.toInt(params.get("number"));
            Integer count = Convert.toInt(params.get("count"));
            String startFlag = Convert.toStr(params.get("startFlag"));
            Integer repeatMode = Convert.toInt(params.get("repeatMode"));
            Integer workTime = Convert.toInt(params.get("workTime"));
            Integer startHour = Convert.toInt(params.get("startHour"));
            Integer startMin = Convert.toInt(params.get("startMin"));

            // 校验消毒机编号格式
            if (!RegexUtils.isNumber(String.valueOf(number), 1)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "消毒机编号格式错误");
                return R.error(400, "消毒机编号格式错误");
            }

            // 校验所修改值的合法性
            if (!(count > 0 && count < 5)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "修改第几条的值只能在1-4之间");
                return R.error(400, "修改第几条的值只能在1-4之间");
            }
            if (!"0".equals(startFlag) && !"1".equals(startFlag)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "开关值只能是0或1-4之间");
                return R.error(400, "开关值只能是0或1-4之间");
            }
            if (!(repeatMode > 0 && repeatMode < 9)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "重复模式值只能在1-8之间");
                return R.error(400, "重复模式值只能在1-8之间");
            }
            if (!(workTime > 0 && workTime < 1000)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "工作时间的值只能在1-999之间");
                return R.error(400, "工作时间的值只能在1-999之间");
            }
            if (!(startHour > -1 && startHour < 24)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "开始小时值只能在0-23之间");
                return R.error(400, "开始小时值只能在0-23之间");
            }
            if (!(startMin > -1 && startMin < 60)) {
                log.warn("方法：{}，错误信息：{}", "定时设置 PC", "开始分钟值只能在0-59之间");
                return R.error(400, "开始分钟值只能在0-59之间");
            }

            boolean mode = HttpUtils.setTimerMode(number, count, Integer.valueOf(startFlag), startMin, workTime, repeatMode, startHour);
            if (!mode) {
                return R.error(400, "请求下位机发生异常");
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "定时设置 PC", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R updateDeviceProduceTime(Map<String, Object> params) {
        try {
            // 获取参数消毒机编号
            String number = Convert.toStr(params.get("number"));

            // 校验消毒机编号格式
            if (!RegexUtils.isNumber(number, 1)) {
                log.warn("方法：{}，错误信息：{}", "出厂按钮 PC", "消毒机编号格式错误");
                return R.error(400, "消毒机编号格式错误");
            }

            // 校验消毒机是否存在
            DeviceEntity deviceEntity = this.getOne(new QueryWrapper<DeviceEntity>().eq("number", number));
            if (deviceEntity == null) {
                log.warn("方法：{}，错误信息：{}", "出厂按钮 PC", "该消毒机不存在");
                return R.error(400, "该消毒机不存在");
            }

            deviceEntity.setProduceTime(new Date());
            boolean update = this.update(deviceEntity, new QueryWrapper<DeviceEntity>().eq("number", number));
            if (update) {
                return R.ok();
            }
            return R.error();
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(400, "系统繁忙");
        }
    }

    /**
     * @param params {number:'',device_type_id:xx,farm_id,name,memo}
     * @return
     */
    @Override
    public R addDevice(Map<String, Object> params) {
        try {
            Long number = Long.valueOf(String.valueOf(params.get("number")));
            Long device_type_id = Long.valueOf(String.valueOf(params.get("device_type_id")));
            Long farm_id = Long.valueOf(String.valueOf(params.get("farm_id")));
            String name = String.valueOf(params.get("name"));
            String memo = String.valueOf(params.get("memo"));
            DeviceEntity deviceEntity = new DeviceEntity();
            deviceEntity.setNumber(number);
            deviceEntity.setDeviceTypeId(device_type_id);
            deviceEntity.setFarmId(farm_id);
            deviceEntity.setName(name);
            deviceEntity.setMemo(memo);
            boolean save = this.save(deviceEntity);
            if (save) {
                return R.ok();
            }
            return R.error();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "新增消毒机 PC", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R updateDevice(Map<String, Object> params) {
        try {
            // 校验消毒机编号
            String number = Convert.toStr(params.get("number"));
            if (!RegexUtils.isNumber(number, 1)) {
                log.warn("方法：{}，错误信息：{}", "修改消毒机 PC", "消毒机编号错误");
                return R.error(400, "消毒机编号错误");
            }

            // 获取参数值
            Long deviceTypeId = Convert.toLong(params.get("device_type_id"));
            Long farmId = Convert.toLong(params.get("farm_id"));
            String name = Convert.toStr(params.get("name"));
            String memo = Convert.toStr(params.get("memo"));

            // 设置值
            DeviceEntity deviceEntity = new DeviceEntity();
            deviceEntity.setDeviceTypeId(deviceTypeId);
            deviceEntity.setFarmId(farmId);
            deviceEntity.setName(name);
            deviceEntity.setMemo(memo);

            // 更新消毒机数据
            boolean update = this.update(deviceEntity, new QueryWrapper<DeviceEntity>().eq("number", number));
            if (update) {
                return R.ok();
            }
            return R.error();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "修改消毒机 PC", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R deleteDevice(Map<String, Object> params) {
        try {
            String number = Convert.toStr(params.get("number"));

            DeviceEntity deviceEntity = this.getOne(new QueryWrapper<DeviceEntity>().eq("number", number));
            if (deviceEntity==null){
                log.error("方法：{}，错误信息：{}", "修改消毒机 PC", "消毒机编号无效");
                return R.error(400, "消毒机编号无效");
            }

            boolean remove = this.remove(new QueryWrapper<DeviceEntity>().eq("number", number));
            if (remove) {
                return R.ok();
            }
            return R.error(400, "消毒机编号无效");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "修改消毒机 PC", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R getDevicesInfo(Map<String, Object> params) {
        try {
            // 获取参数设备编号
            String deviceId = Convert.toStr(params.get("device_id"));

            // 校验设备编号格式
            if (!RegexUtils.isNumber(String.valueOf(deviceId), 1)) {
                log.warn("方法：{}，错误信息：{}", "获取消毒机信息", "消毒机编号格式错误");
                return R.error(400, "消毒机编号格式错误");
            }

            // 查询设备信息
            DeviceEntity device = this.getOne(new QueryWrapper<DeviceEntity>().eq("number", deviceId));

            // 校验设备是否为空
            if (device == null) {
                log.warn("方法：{}，错误信息：{}", "获取消毒机信息", "消毒机编号无效");
                return R.error(400, "消毒机编号无效");
            }
            if (device.getSampleTime() == null) {
                log.warn("方法：{}，错误信息：{}", "获取消毒机信息", "消毒机采集时间为空");
                return R.error(400, "消毒机采集时间为空");
            }

            // 计算采集时间和目前时间的时间差（分钟）
            Date sampleTime = device.getSampleTime();
            Date date = new Date();
            long minute = DateUtil.between(sampleTime, date, DateUnit.MINUTE);
            if (minute > 1) {
                device.setStatus(1);
            } else {
                device.setStatus(0);
            }
            FarmEntity farmEntity = farmService.getById(device.getFarmId());
            if (farmEntity == null) {
                device.setFarmName("");
            }
            device.setFarmName(farmEntity.getName());
            return R.ok().put("data", device);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("方法：{}，错误信息：{}", "获取消毒机信息", e.getMessage());
            return R.error(400, "系统繁忙");
        }
    }

    @Override
    public R setSystemTime(Map<String, Object> params) {
        Object number = params.get("number");
        Object year = params.get("year");
        Object mon = params.get("mon");
        Object day = params.get("day");
        Object hour = params.get("hour");
        Object min = params.get("min");
        Object sec = params.get("sec");
        Object week = params.get("week");
        boolean setSystemTime = HttpUtils.setSystemTime(number, year, mon, day, hour, min, sec, week);
        if (!setSystemTime) {
            log.warn("方法：{}，错误信息：{}", "设置系统时间", "设置系统时间失败");
            return R.error(400, "设置系统时间失败");
        }
        return R.ok();
    }

    public Integer getCount(Map<String, Object> params) {
        int count = 0;
        Object farm = params.get("farm");
        Object type = params.get("type");
        Object number = params.get("number");
        Object name = params.get("name");
        Object status = params.get("status");
        Object produce_time = params.get("produce_time");
        Object sale_time = params.get("sale_time");
        Object mode = params.get("mode");
        if (!farm.equals("")) {
            count++;
        }
        if (!type.equals("")) {
            count++;
        }
        if (!name.equals("")) {
            count++;
        }
        if (!number.equals("")) {
            count++;
        }
        if (!status.equals("")) {
            count++;
        }
        if (!produce_time.equals("")) {
            count++;
        }
        if (!sale_time.equals("")) {
            count++;
        }
        if (!mode.equals("")) {
            count++;
        }
        return count;
    }

    public ReturnDeviceEntityVo getDeviceVo(DeviceEntity deviceEntity) {
        ReturnDeviceEntityVo deviceVo = new ReturnDeviceEntityVo();
        FarmEntity farmEntity = farmService.getById(deviceEntity.getFarmId());
        DeviceTypeEntity deviceTypeEntity = deviceTypeService.getById(deviceEntity.getDeviceTypeId());
        if (farmEntity == null || deviceTypeEntity == null) {
            return null;
        }
        deviceVo.setFarm(farmEntity.getName());
        deviceVo.setType(deviceTypeEntity.getName());
        deviceVo.setNumber(deviceEntity.getNumber());
        deviceVo.setName(deviceEntity.getName());
        deviceVo.setStatus(deviceEntity.getStatus());
        deviceVo.setProduceTime(deviceEntity.getProduceTime());
        deviceVo.setSaleTime(deviceEntity.getSaleTime());
        deviceVo.setMode(deviceEntity.getMode());
        return deviceVo;
    }
}